package com.appspot.abcensys.server;

import java.util.ArrayList;
import java.util.TreeMap;
import java.util.logging.Logger;

import com.appspot.abcensys.client.AbcensysService;
import com.appspot.abcensys.shared.Afwezigheid;
import com.appspot.abcensys.shared.FntRoosterInfo;
import com.appspot.abcensys.shared.Gebruiker;
import com.appspot.abcensys.shared.GebruikerInstelling;
import com.appspot.abcensys.shared.Les;
import com.appspot.abcensys.shared.RoosterSupplier;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * AsyncService implementatie communiceerd weer met de AbcensysServer
 * 
 * @author Hugo Zonderland
 */
public class AbcensysServiceImpl extends RemoteServiceServlet implements AbcensysService {

	private static final long serialVersionUID = 1L;

	// AbcensysServer
	private AbcensysServer server = new AbcensysServer();

	// Logger
	private static final Logger log = Logger.getLogger(AbcensysServiceImpl.class.getName());

	// CalendarSupploer
	private CalendarSupplier cal = new CalendarSupplier();

	// FnRoosterInfo
	private FntRoosterInfo fri = new FntRoosterInfo();

	// Installtie controle
	/**
	 * Controleerd of het systeem "nieuw" is en dwingt zo het toevoegen van een
	 * Gebruiker object met isAdministrator attribuut
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#getGebruikers()
	 * @return true wanneer er geen Gebruiker objecten bestaan
	 */
	public boolean installatieModus() {
		boolean b = false;
		// Zijn er Gebruiker objecten
		ArrayList<Gebruiker> gebruikers = server.getGebruikers();
		if (gebruikers != null && gebruikers.isEmpty()) {
			b = true;
		} else {
			// Is er 1 Gebruiker Admin?
			for (Gebruiker gebruiker : gebruikers) {
				if (gebruiker.getIsAdministrator()) {
					b = false;
				}
			}
		}
		return b;
	}

	// GEBRUIKER
	/**
	 * Haalt de huidige ingelogde Gebruiker op
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#getHuidigeGebruiker()
	 * @return Gebruiker die op dit moment ingelogd is
	 */
	public Gebruiker getHuidigeGebruiker() {
		return server.getHuidigeGebruiker();
	}

	/**
	 * Haalt een List<Gebruiker> op met Gebruiker objecten
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#getGebruikers()
	 * @return List<Gebruiker> met Gebruiker objecten
	 */
	public ArrayList<Gebruiker> getGebruikers() {
		return server.getGebruikers();
	}

	/**
	 * Haalt een Gebruiker object op a.d.v. een email adres
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#getGebruikerByEmail(String)
	 * @param String
	 *            met email adres van de Gebruiker
	 * @return Gebruiker object
	 */
	public Gebruiker getGebruikerByEmail(String email) {
		return server.getGebruikerByEmail(email);
	}

	/**
	 * Haalt het totaal aantal Gebruiker objecten op a.d.v een vakcode
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#getAantalGebruikersByKlascode(String)
	 * @see com.appspot.abcensys.server.AbcensysServer#getLesByVakCode(String)
	 * @param String
	 *            vakcode waar opgezocht word
	 * @return int met aantal studenten * lessen
	 */
	public int getAantalGebruikersByVakcode(String vakcode) {
		// Haalt de Les objecten op a.d.v de vakcode
		ArrayList<Les> lessen = server.getLesByVakCode(vakcode);
		// Haalt het aantal gebruikers op bij de klascode
		int studenten = server.getAantalGebruikersByKlascode(lessen.get(0).getKlasCode());
		// Totaal aantal studenten is dan lessen * studenten
		return lessen.size() * studenten;
	}

	/**
	 * Slaat een Gebruiker object op
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#addGebruiker(Gebruiker);
	 * @param Gebruiker
	 *            object die opgeslagen moet worden
	 * @return Gebruiker object welke net is opgeslagen
	 */
	public Gebruiker addGebruiker(Gebruiker gebruiker) {
		return server.addGebruiker(gebruiker);
	}

	/**
	 * Update een Gebruiker object
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#updateGebruiker(Gebruiker)
	 * @param Gebruiker
	 *            object wat word geupdate
	 * @return Gebruiker object die net geupdate is
	 */
	public Gebruiker updateGebruiker(Gebruiker g) {
		return server.updateGebruiker(g);
	}

	// AFWEZIGHEID
	/**
	 * Haalt alle Afwezigheid objecten op van de huidige ingelgode Gebruiker
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#getAfwezigheidVoorGebruiker(Gebruiker)
	 * @return List<Afwezigheid> met alle Afwezigheidsregistraties
	 */
	public ArrayList<Afwezigheid> getAfwezigheidVoorStudent() {
		return server.getAfwezigheidVoorGebruiker(server.getHuidigeGebruiker());
	}

	/**
	 * Haalt alle Afwezigheid van een Gebruiker op a.d.v zijn klascode.
	 * Gesorteerd op Vakcode.
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#getGebruikerVakCodesByKlasCode(String)
	 * @see com.appspot.abcensys.server.AbcensysServer#getGebruikerAfwezigheidByVakcode(String)
	 * @return TreeMap<String, ArrayList<Afwezigheid>> met registraties per
	 *         vakcode
	 */
	public TreeMap<String, ArrayList<Afwezigheid>> getAfwezigheidVoorStudentDashboard() {
		TreeMap<String, ArrayList<Afwezigheid>> tmRegistraties = new TreeMap<String, ArrayList<Afwezigheid>>();

		// Vakcodes ophalen van de Gebruiker
		ArrayList<String> vakcodes = server.getGebruikerVakCodesByKlasCode(server.getHuidigeGebruiker().getKlasCode());
		for (String vakcode : vakcodes) {
			// Afwezigheden per vakcode ophalen
			ArrayList<Afwezigheid> afwezigheid = server.getGebruikerAfwezigheidByVakcode(vakcode);
			if (afwezigheid != null && !afwezigheid.isEmpty()) {
				// Toevoegen
				tmRegistraties.put(vakcode, afwezigheid);
			} else {
				// Anders legen array plaatsen
				tmRegistraties.put(vakcode, new ArrayList<Afwezigheid>());
			}
		}
		return tmRegistraties;
	}

	/**
	 * Haalt alle Afwezigheid objecten op die bij een Les gegeven door een
	 * Docent horen.
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#getLessenByDocent()
	 * @see com.appspot.abcensys.server.AbcensysServer#getAfwezigheidPerLes(Long)
	 * @return TreeMap<String, ArrayList<Afwezigheid>> met de vakcode met
	 *         daaraan gekoppeld de Afwezigheids registraties
	 */
	public TreeMap<String, ArrayList<Afwezigheid>> getAfwezigheidVoorDocent() {
		TreeMap<String, ArrayList<Afwezigheid>> afwPvakCode = new TreeMap<String, ArrayList<Afwezigheid>>();

		// Lessen ophalen gegeven door de docent
		ArrayList<Les> docentLessen = server.getLessenByDocent();

		if (docentLessen != null && !docentLessen.isEmpty()) {
			for (Les les : docentLessen) {

				ArrayList<Afwezigheid> registraties = new ArrayList<Afwezigheid>();

				// Registraties per les ophalen en toevoegen
				for (Afwezigheid a : server.getAfwezigheidPerLes(les.getId())) {
					registraties.add(a);
				}

				// Wanneer de vakcode nog niet voorkomt aan de TreeMap toevoegen
				if (afwPvakCode.get(les.getVakCode()) == null) {
					afwPvakCode.put(les.getVakCode(), registraties);
				} else {
					// Anders alle Afwezigheid registraties toevoegen
					ArrayList<Afwezigheid> combi = afwPvakCode.get(les.getVakCode());
					combi.addAll(registraties);
					afwPvakCode.put(les.getVakCode(), combi);
				}

			}
		}
		return afwPvakCode;
	}

	/**
	 * Haalt van alle Lessen de Afwezigheid op
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#getVakCodes()
	 * @see com.appspot.abcensys.server.AbcensysServer#getLesByVakCode(String)
	 * @see com.appspot.abcensys.server.AbcensysServer#getAfwezigheidPerLes(Long)
	 * @return TreeMap<Les, ArrayList<Afwezigheid>> met alle Afwezigheid
	 *         registraties per les
	 */
	public TreeMap<String, ArrayList<Afwezigheid>> getAlleAfwezigheidPerVak() {
		TreeMap<String, ArrayList<Afwezigheid>> tmRegistraties = new TreeMap<String, ArrayList<Afwezigheid>>();

		// Haalt alle vakcodes op
		ArrayList<String> vakCodes = server.getVakCodes();
		for (String vak : vakCodes) {

			// Haalt de lessen met de vakcode op
			ArrayList<Les> lessen = server.getLesByVakCode(vak);
			ArrayList<Afwezigheid> registraties = new ArrayList<Afwezigheid>();

			for (Les les : lessen) {
				// Haalt de Afwezigheid registraties op per Les.
				for (Afwezigheid afwezigheid : server.getAfwezigheidPerLes(les.getId())) {
					registraties.add(afwezigheid);
				}
			}
			tmRegistraties.put(vak, registraties);
		}
		return tmRegistraties;
	}

	/**
	 * Haalt het aantal Afwezigheidregistraties per instituut/faculteit op
	 * 
	 * @
	 * @return TreeMap<String, TreeMap<Integer, Integer>> met per instituut het
	 *         aantal afmeldingen en totalen per les.
	 */
	public TreeMap<String, TreeMap<Integer, Integer>> getAfwezigheidPerInstituut() {
		// Cijfers
		TreeMap<String, TreeMap<Integer, Integer>> instituutcijfers = new TreeMap<String, TreeMap<Integer, Integer>>();

		// Instituten ophalen
		ArrayList<String> faculteiten = (ArrayList<String>) fri.getFaculteiten();

		for (String faculteit : faculteiten) {
			TreeMap<Integer, Integer> aanafwezigen = new TreeMap<Integer, Integer>();

			int afwezigen = 0;
			int aanwezigen = 0;

			// Lessen per faculteit/instituut ophalen
			ArrayList<Les> faculteitLessen = server.getLesByFaculteit(faculteit);
			for (Les les : faculteitLessen) {
				// Afwezigen optellen
				afwezigen += server.getAfwezigheidPerLes(les.getId()).size();
				// Aanwezigen is het aantal studenten per klascode (is altijd
				// het zelfde)
				aanwezigen += server.getAantalGebruikersByKlascode(les.getKlasCode());
			}

			aanafwezigen.put(afwezigen, aanwezigen);
			instituutcijfers.put(fri.getFaculteitNaam(faculteit), aanafwezigen);
		}

		return instituutcijfers;
	}

	/**
	 * Slaat een Afwezigheid object op
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#addAfwezig(Afwezigheid);
	 * @param ArrayList
	 *            <String> met lesId's
	 * @param String
	 *            met de afwezigheids categorie
	 * @param String
	 *            met de toelichting
	 * @return true wanneer gelukt op te slaan, anders false
	 */
	public boolean addAfwezigheid(ArrayList<String> lessen, String categorie, String toelichting) {
		ArrayList<Afwezigheid> afwezigheden = new ArrayList<Afwezigheid>();
		// Door de lessen heen lopen
		for (String les : lessen) {
			// Checken of de Student niet afwezig is gemeld
			if (!server.isStudentAfwezigInLes(Long.parseLong(les))) {
				Afwezigheid a = new Afwezigheid();

				a.setEmail(this.getHuidigeGebruiker().getEmail());
				a.setLesId(Long.parseLong(les));
				a.setVerzuimCategorie(categorie);
				a.setToelichting(toelichting);

				afwezigheden.add(a);
			}
		}
		if (afwezigheden != null && afwezigheden.isEmpty()) {
			return false;
		}
		return server.addAfwezig(afwezigheden);
	}

	/**
	 * Verwijderd een Afwezigheid object
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#verwijderAfwezigheidById(Long)
	 * @param Long
	 *            met de Afwezigheid Id
	 * @return true wanneer gelukt te verwijderen, anders false
	 */
	public boolean verwijderAfwezigheid(Afwezigheid a) {
		return server.verwijderAfwezigheid(a);
	}

	/**
	 * Verwijderd een Afwezigheid object
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#verwijderAfwezigheidByIdTrancient(Long)
	 * @param Long
	 *            met de Afwezigheid Id
	 * @return true wanneer gelukt te verwijderen, anders false
	 */
	public boolean verwijderAfwezigheidByIdTrancient(Long afwezigheidId) {
		return server.verwijderAfwezigheidByIdTrancient(afwezigheidId);
	}

	/**
	 * Verwijderd een Afwezigheid obect a.d.v de lesId en email adres
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#verwijderAfwezigheidByLesIdAndGebruiker(String)
	 * @param String
	 *            met Les Id
	 * @return true wanneer gelukt, false wanneer niet
	 */
	public boolean verwijderAfwezigheidByLesIdAndGebruiker(String lesId) {
		return server.verwijderAfwezigheidByLesIdAndGebruiker(lesId);
	}

	// LES
	/**
	 * Haalt een les op a.d.v zijn Id
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#getLesById(Long);
	 * @param Long
	 *            met het Les Id.
	 * @return Les object
	 */
	public Les getLesById(Long id) {
		return server.getLesById(id);
	}

	/**
	 * Haalt het Les rooster van de student op en bepaald of de student zich al
	 * Afwezigheid heeft gemeld per Les
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#getLesByKlasAndDatumVandaagEnMorgen(String,
	 *      String, String)
	 * @return TreeMap<Les, Boolean> met Les en Afwezigheid per Les
	 */
	public TreeMap<Les, Boolean> getLesRooster() {
		// Datum vandaag & morgen bepalen
		String datumVandaag = cal.getDatumVandaag();
		String datumMorgen = cal.getDatumMorgen();

		Gebruiker g = server.getHuidigeGebruiker();
		// TODO: moet actief worden
		// ArrayList<Les> lessen = server.getLesByKlasAndDatumVandaagEnMorgen(g.getKlasCode(), datumVandaag, datumMorgen);
		// Rooster ophalen
		ArrayList<Les> lessen = server.getLesByKlasAndWeeknummer(g.getKlasCode(), 45);
		TreeMap<Les, Boolean> tm = new TreeMap<Les, Boolean>();
		if (lessen != null && !lessen.isEmpty()) {
			for (Les les : lessen) {
				// Les en bepalen of Student afwezig is voor de les
				tm.put(les, server.isStudentAfwezigInLes(les.getId()));
			}
		} else {
			RoosterSupplier rs = new RoosterSupplier();
			rs.getRooster(this.getHuidigeGebruiker());
		}
		return tm;
	}

	/**
	 * Haalt het aantal lessen op die zijn geweest/komen
	 * 
	 * @param String
	 *            met klascode
	 * @param String
	 *            met vakcode
	 * @return int met het aantal lessen die zijn geweest
	 */
	public int getTotaalAantalLessenByKlasAndVakcode(String klascode, String vakcode) {
		return server.getTotaalAantalLessenByKlasAndVakcode(klascode, vakcode);
	}

	// GEBRUIKERINSTELLING
	/**
	 * Haalt de instellingen van een Gebruiker op
	 * 
	 * @return GebruikerInstelling van de Gebruiker, anders null
	 */
	public GebruikerInstelling getGebruikerInstelling() {
		return server.getGebruikerInstelling();
	}

	/**
	 * Update de GebruikerInstellingen
	 * 
	 * @see com.appspot.abcensys.server.server.AbcensysServer#
	 *      updateGebruikerInstelling(ArrayList<Boolean>)
	 * @param ArrayList
	 *            <Boolean> met de instellingen
	 * @return true wanneer gelukt te wijzigen, false wanneer niet
	 */
	public boolean updateGebruikerInstelling(ArrayList<Boolean> instellingen) {
		return server.updateGebruikerInstelling(instellingen);
	}

	// MENU GERELATEERDE FUNCTIES
	/**
	 * Haalt de Login URL op
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#getLoginUrl();
	 * @return String met LoginUrl
	 */
	public String getLoginUrl() {
		return server.getLoginUrl();
	}

	/**
	 * Haalt de Logout Url op
	 * 
	 * @see com.appspot.abcensys.server.AbcensysServer#getLogoutUrl();
	 * @return String met LogoutUrl
	 */
	public String getLogoutUrl() {
		return server.getLogoutUrl();
	}

	// CALENDARSERVLET
	/**
	 * Haalt het huidige jaar op
	 * 
	 * @see com.appspot.abcensys.shared.CalendarSupplier#getJaar();
	 * @return Integer met het huidige jaar
	 */
	public int getJaar() {
		return cal.getJaar();
	}

	/**
	 * Haalt de huidige weeknummer op
	 * 
	 * @see com.appspot.abcensys.shared.CalendarSupplier#getWeekNummer();
	 * @return Integer met huidige weeknummer
	 */
	public int getWeekNummer() {
		return cal.getWeekNummer();
	}

	/**
	 * @see com.appspot.abcensys.client.AbcensysService#setGebruiker(com.appspot.
	 *      abcensys.shared.Gebruiker)
	 */
	@Override
	public Void setHuidigeGebruiker(Gebruiker g) {
		this.server.setHuidigeGebruiker(g);
		return null;
	}
}
